﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Diagnostics;

namespace Xceed.Silverlight.Data
{
  [DebuggerDisplay( "Value = {DebuggerDisplayValue}, IsEstimate = {DebuggerDisplayIsEstimate}, ReferencePosition = {ReferencePosition}" )]
  internal class RelativeOffset
  {
    internal RelativeOffset( long value, ReferencePoint point )
    {
      this.EstimateValue = value;
      this.ReferencePosition = point;
    }

    internal RelativeOffset( EstimateInt64 value, ReferencePoint point )
    {
      if( value == null )
        throw new ArgumentNullException( "value" );

      this.EstimateValue = value;
      this.ReferencePosition = point;
    }


    #region DebuggerDisplayValue Property

    private long DebuggerDisplayValue
    {
      get
      {
        return this.EstimateValue.Value;
      }
    }

    #endregion DebuggerDisplayValue Property

    #region DebuggerDisplayIsEstimate Property

    private bool DebuggerDisplayIsEstimate
    {
      get
      {
        return this.EstimateValue.IsEstimate;
      }
    }

    #endregion DebuggerDisplayIsEstimate Property

    #region ReferencePosition Property

    internal ReferencePoint ReferencePosition
    {
      get;
      private set;
    }

    #endregion ReferencePosition Property

    #region EstimateValue Property

    internal EstimateInt64 EstimateValue
    {
      get;
      set;
    }

    #endregion EstimateValue Property

    #region Value Property

    public long Value
    {
      get
      {
        return this.EstimateValue.Value;
      }
    }

    #endregion Value Property

    #region IsEstimate Property

    public bool IsEstimate
    {
      get
      {
        return this.EstimateValue.IsEstimate;
      }
    }

    #endregion IsEstimate Property

    public static bool operator ==( RelativeOffset x, RelativeOffset y )
    {
      if( object.ReferenceEquals( x, y ) )
        return true;

      if( object.ReferenceEquals( x, null ) )
        return y.Equals( x );

      return x.Equals( y );
    }

    public static bool operator !=( RelativeOffset x, RelativeOffset y )
    {
      return !( x == y );
    }

    public override int GetHashCode()
    {
      return this.ReferencePosition.GetHashCode() ^ this.EstimateValue.GetHashCode();
    }

#if DEBUG
    public override string ToString()
    {
      return string.Format( "(Val={0}, Est={1}, Ref={2})", this.Value, this.IsEstimate, this.ReferencePosition );
    }
#endif  //DEBUG

    public override bool Equals( object obj )
    {
      RelativeOffset value = obj as RelativeOffset;

      if( object.ReferenceEquals( value, null ) )
        return false;

      if( object.ReferenceEquals( value, this ) )
        return true;

      if( value.GetHashCode() != this.GetHashCode() )
        return false;

      return object.Equals( value.ReferencePosition, this.ReferencePosition )
          && object.Equals( value.EstimateValue, this.EstimateValue );
    }

    public static RelativeOffset operator +( RelativeOffset self, EstimateInt64 value )
    {
      RelativeOffset.CheckForNull( self, "self" );
      RelativeOffset.CheckForNull( value, "value" );

      return ( RelativeOffset.IsAdditiveIdentity( value ) )
               ? self
               : new RelativeOffset( self.EstimateValue + value, self.ReferencePosition );
    }

    public static RelativeOffset operator +( RelativeOffset self, long scalar )
    {
      RelativeOffset.CheckForNull( self, "self" );

      return ( RelativeOffset.IsAdditiveIdentity( scalar ) )
               ? self
               : new RelativeOffset( self.EstimateValue + scalar, self.ReferencePosition );
    }

    public static RelativeOffset operator -( RelativeOffset self, EstimateInt64 value )
    {
      RelativeOffset.CheckForNull( self, "self" );
      RelativeOffset.CheckForNull( value, "value" );

      return ( RelativeOffset.IsAdditiveIdentity( value ) )
               ? self
               : new RelativeOffset( self.EstimateValue - value, self.ReferencePosition );
    }

    public static RelativeOffset operator -( RelativeOffset self, long scalar )
    {
      RelativeOffset.CheckForNull( self, "self" );

      return ( RelativeOffset.IsAdditiveIdentity( scalar ) )
               ? self
               : new RelativeOffset( self.EstimateValue - scalar, self.ReferencePosition );
    }

    private static void CheckForNull( RelativeOffset value, string parameterName )
    {
      if( value == null )
        throw new ArgumentNullException( parameterName );
    }

    private static void CheckForNull( EstimateInt64 value, string parameterName )
    {
      if( value == null )
        throw new ArgumentNullException( parameterName );
    }

    private static bool IsAdditiveIdentity( EstimateInt64 value )
    {
      return ( RelativeOffset.IsAdditiveIdentity( value.Value ) && !value.IsEstimate );
    }

    private static bool IsAdditiveIdentity( long scalar )
    {
      return ( scalar == 0 );
    }
  }
}
